package jp.anago_dev.takarush_helper.location;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;

/**
 * 位置情報取得サービスクラスです。
 * 
 * @author anago_dev
 * 
 */
public class LocationService extends Service {

    /** インテントキー(位置情報プロバイダ) */
    public static final String INTENT_KEY_PROVIDER = "jp.anago_dev.takarush_helper.provider";

    /** インテントキー(位置情報更新間隔[millis]) */
    public static final String INTENT_KEY_LOCATION_INTERVAL = "jp.anago_dev.takarush_helper.location_interval";

    /** 更新のデフォルト周期 */
    public static final int DEFAULT_LOCATION_UPDATE_INTERVAL = 60 * 1000;

    /** 位置情報プロバイダ名 */
    private String mProviderName;

    /** 更新周期 */
    private int mUpdateInterval;

    /** LocationManagerオブジェクト */
    private LocationManager mLocationManager;

    /** {@link RemoteCallbackList} */
    private final RemoteCallbackList<IUpdateLocationCallback> mCallbackList = new RemoteCallbackList<IUpdateLocationCallback>();

    /** 現在地取得リスナ */
    private final LocationListener mLocationListener = new LocationListener() {

        @Override
        public void onLocationChanged(Location location) {
            updateLocation(location);
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }

        @Override
        public void onProviderEnabled(String provider) {
        }

        @Override
        public void onProviderDisabled(String provider) {
        }
    };

    /** 現在地サービススタブ */
    private final ILocationService.Stub mLocationServiceStub = new ILocationService.Stub() {

        @Override
        public void stopService() throws RemoteException {
            mLocationManager.removeUpdates(mLocationListener);
        }

        @Override
        public void registerUpdateLocationCallback(IUpdateLocationCallback callback) throws RemoteException {
            if (callback != null) {
                mCallbackList.register(callback);
            }
        }

        @Override
        public void unregisterUpdateLocationCallback(IUpdateLocationCallback callback) throws RemoteException {
            if (callback != null) {
                mCallbackList.unregister(callback);
            }
        }
    };

    /**
     * @see android.app.Service#onBind(android.content.Intent)
     */
    @Override
    public IBinder onBind(final Intent intent) {

        if (ILocationService.class.getName().equals(intent.getAction())) {
            init(intent);
            return mLocationServiceStub;
        }

        return null;
    }

    /**
     * 初期化を行います。<br/>
     * 現在地の取得を行います。
     */
    private void init(final Intent intent) {

        // プロバイダ名取得
        mProviderName = intent.getStringExtra(INTENT_KEY_PROVIDER);
        // 更新間隔取得（なければデフォルト値）
        mUpdateInterval = intent.getIntExtra(INTENT_KEY_LOCATION_INTERVAL, DEFAULT_LOCATION_UPDATE_INTERVAL);

        mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

        // プロバイダ設定なし、または設定OFFなら通知しない
        if (mProviderName == null || (mProviderName != null && !mLocationManager.isProviderEnabled(mProviderName))) {
            return;
        }

        mLocationManager.requestLocationUpdates(mProviderName, mUpdateInterval, 0, mLocationListener);

    }

    /**
     * 現在地を更新します。
     * 
     * @param location
     *            {@link Location}オブジェクト
     */
    private void updateLocation(final Location location) {

        final double latitude = location.getLatitude();
        final double longitude = location.getLongitude();
        final long time = location.getTime();
        final float accuracy = location.getAccuracy();

        final int length = mCallbackList.beginBroadcast();

        // コールバック通知
        for (int i = 0; i < length; i++) {
            try {
                mCallbackList.getBroadcastItem(i).updateLocation(latitude, longitude, time, accuracy);
            } catch (RemoteException e) {
                e.printStackTrace();
            } finally {
                mCallbackList.finishBroadcast();
            }
        }
    }

}
